<template>
  <div class="netcall-container" v-loading="loading">
    <div class="netcall-box">
      <Avatar :src="info.mastAvatarSrc "/>

      <div class="nickname">{{ info.mastName }}</div>

      <div class="tips">
        <CallingTip v-if="state === STATUS.calling" />
        <CallingTimer v-else-if="state === STATUS.talking"/>
      </div>

      <div class="control">
        <template v-if="state === STATUS.talking">
          <!-- 话筒 -->
          <Controller :max="10" :defaultValue="10" @change="handleCaptureVolumeChange">
            <template v-slot:yes>
              <i class="el-icon-microphone" ></i>
            </template>
            <template v-slot:no>
              <i class="el-icon-turn-off-microphone" ></i>
            </template>
          </Controller>

          <!-- 听筒 -->
          <Controller :max="10" :defaultValue="10" @change="handlePalyVolumeChange">
            <template v-slot:yes>
              <i class="iconfont icon-volume-open" ></i>
            </template>
            <template v-slot:no>
              <i class="iconfont icon-volume-off" ></i>
            </template>
          </Controller>
        </template>
      </div>

      <div class="actions">
        <el-button v-if="isFree" type="success" icon="el-icon-phone" circle @click="makeAudioCall"></el-button>
        <el-button v-if="isBusy" type="danger" icon="el-icon-phone-outline" circle @click="cancelAudioCall"></el-button>
      </div>
    </div>
  </div>
</template>

<script>
import axios from 'axios';
import Avatar from './components/Avatar';
import CallingTip from './components/CallingTip';
import CallingTimer from './components/CallingTimer';
import Controller from './components/Controller';
import { APP_KEY, STATUS } from '@/config';
import { errorMessage, successMessage, infoMessage } from '@/utils/message';
import Ring from '@/utils/Ring';

const NIM = window.NIM;
const WebRTC = window.WebRTC;

NIM.use(WebRTC);

export default {
  name: 'Netcall',
  components: {
    Avatar,
    CallingTip,
    CallingTimer,
    Controller
  },
  data () {
    return {
      STATUS,
      loading: true,
      nim: null,
      netcall: null,
      info: {
      },
      state: STATUS.free,
      callTimer: null
    };
  },
  computed: {
    isFree () {
      return this.state === STATUS.free;
    },
    isBusy () {
      return this.state === STATUS.calling || this.state === STATUS.talking;
    }
  },
  mounted () {
    const { masterId } = this.$route.query;

    if (!masterId) {
      this.$alert('缺少必要的师傅信息，语音功能不可用', '发生错误', {
        confirmButtonText: '知道了',
        type: 'error'
      });

      return;
    }
    // eslint-disable-next-line
    if (__DEV__) {
      this.loading = false;
      this.info = {
        mastAvatarSrc: 'https://img1.xiujiadian.com/dev/mapp/201902/20190219141252_935991.jpg',
        mastImId: '67311MeP8Nq67g5wTUp44T8QOq47fvq7',
        mastName: '满意加盟师傅',
        staffImId: '6P4wR41F3Wv94iEkW3zyqq9PpC844S6R',
        staffImToken: 'a26974c06a06939ae98500613ad19c40'
      };

      this.initCallComponent();
    }

    // eslint-disable-next-line
    if (!__DEV__) {
      this.fetchNetcallInfo(masterId).then((response) => {
        const { data } = response;
        if (response.status === 200 && data.statusBool) {
          this.info = data.data;
          this.initCallComponent();
        } else {
          errorMessage('数据初始化失败');
        }
      });
    }
  },
  methods: {
    fetchNetcallInfo (masterId) {
      return axios.get(`/netcall/im/info?mastId=${masterId}`);
    },
    handleCaptureVolumeChange (value) {
      this.setCaptureVolume(parseInt(255 * value / 10));
    },
    handlePalyVolumeChange (value) {
      this.setPlayVolume(parseInt(255 * value / 10));
    },
    initCallComponent () {
      this.initNIM().then((nim) => {
        this.nim = nim;
        this.initNetcall();
        this.loading = false;
        // iframe 关闭回调
        if (window.netcallInfo) {
          window.netcallInfo.netcall = this.netcall;
        }

        // 初始化成功后立即拨打电话
        this.makeAudioCall();
      }).catch(() => {
        errorMessage('网络电话组件初始化失败！');
      });
    },
    initNIM () {
      const { staffImId, staffImToken } = this.info;

      return new Promise((resolve, reject) => {
        const nim = NIM.getInstance({
          debug: true,
          db: false,
          appKey: APP_KEY,
          account: staffImId,
          token: staffImToken,
          onconnect: (msg) => {
            resolve(nim);
          },
          ondisconnect: () => {
            errorMessage('连接断开');
            if (this.netcall) {
              this.cancelAudioCall();
            }
          },
          onerror: () => {
            errorMessage('发生错误');
            if (this.netcall) {
              this.cancelAudioCall();
            }
          }
        });
      });
    },
    initNetcall () {
      this.netcall = WebRTC.getInstance({
        debug: true,
        nim: this.nim,
        container: null,
        remoteContainer: null
      });

      this.initNetcallEvent();
    },
    setCaptureVolume (value) {
      this.netcall.setCaptureVolume(value);
    },
    setPlayVolume (value) {
      this.netcall.setPlayVolume(value);
    },
    initNetcallEvent () {
      const netcall = this.netcall;

      netcall.on('callAccepted', obj => {
        this.onCallAccepted();
      });

      netcall.on('hangup', obj => {
        this.onHangup();
      });

      netcall.on('callRejected', obj => {
        // clearCallTimer()
        errorMessage('呼叫被拒绝，请稍后再试！');
        this.onCallRejected();
      });

      // 通话过程中，WebRTC连接断开
      netcall.on('rtcConnectFailed', (event) => {
        errorMessage('连接断开，请稍后再试！');
      });

      // 控制
      netcall.on('control', (event) => {
        // 如果不是当前通话的指令, 直接丢掉
        if (netcall.notCurrentChannelId(event)) {
          return;
        }
        const { type } = event;
        switch (type) {
          // NETCALL_CONTROL_COMMAND_NOTIFY_AUDIO_ON 通知对方自己打开了音频
          case WebRTC.NETCALL_CONTROL_COMMAND_NOTIFY_AUDIO_ON:
            this.log('对方打开了音频');
            // infoMessage('对方打开了音频');
            break;
          // NETCALL_CONTROL_COMMAND_NOTIFY_AUDIO_OFF 通知对方自己关闭了音频
          case WebRTC.NETCALL_CONTROL_COMMAND_NOTIFY_AUDIO_OFF:
            this.log('对方关闭了音频');
            infoMessage('对方关闭了音频');
            break;
          // NETCALL_CONTROL_COMMAND_NOTIFY_VIDEO_ON 通知对方自己打开了视频
          case WebRTC.NETCALL_CONTROL_COMMAND_NOTIFY_VIDEO_ON:
            this.log('对方打开了视频');
            break;
          // NETCALL_CONTROL_COMMAND_NOTIFY_VIDEO_OFF 通知对方自己关闭了视频
          case WebRTC.NETCALL_CONTROL_COMMAND_NOTIFY_VIDEO_OFF:
            this.log('对方关闭了视频');
            break;
          // NETCALL_CONTROL_COMMAND_SWITCH_AUDIO_TO_VIDEO 请求从音频切换到视频
          case WebRTC.NETCALL_CONTROL_COMMAND_SWITCH_AUDIO_TO_VIDEO:
            this.log('对方请求从音频切换到视频通话');
            break;
          // NETCALL_CONTROL_COMMAND_SWITCH_AUDIO_TO_VIDEO_REJECT 拒绝从音频切换到视频
          case WebRTC.NETCALL_CONTROL_COMMAND_SWITCH_AUDIO_TO_VIDEO_REJECT:
            this.log('对方拒绝从音频切换到视频通话');
            break;
          // NETCALL_CONTROL_COMMAND_SWITCH_AUDIO_TO_VIDEO_AGREE 同意从音频切换到视频
          case WebRTC.NETCALL_CONTROL_COMMAND_SWITCH_AUDIO_TO_VIDEO_AGREE:
            this.log('对方同意从音频切换到视频通话');
            break;
          // NETCALL_CONTROL_COMMAND_SWITCH_VIDEO_TO_AUDIO 从视频切换到音频
          case WebRTC.NETCALL_CONTROL_COMMAND_SWITCH_VIDEO_TO_AUDIO:
            this.log('对方同意从视频切换到音频');
            break;
          // NETCALL_CONTROL_COMMAND_BUSY 占线
          case WebRTC.NETCALL_CONTROL_COMMAND_BUSY:
            errorMessage('对方正在通话中');
            this.log('对方同意从从视频切换到音频');
            Ring.playBusyRing(() => {
              this.cancelAudioCall();
            });
            break;
          // NETCALL_CONTROL_COMMAND_SELF_CAMERA_INVALID 自己的摄像头不可用
          // NETCALL_CONTROL_COMMAND_SELF_ON_BACKGROUND 自己处于后台
          // NETCALL_CONTROL_COMMAND_START_NOTIFY_RECEIVED 告诉发送方自己已经收到请求了（用于通知发送方开始播放提示音）
        }
      });

      netcall.on('remoteTrack', (obj) => {
        if (obj.track && obj.track.kind === 'audio') {
          this.log('启动播放对方声音的设备');
          this.startDeviceAudioOutChat();
        }
      });
    },
    makeAudioCall () {
      // 音频
      // eslint-disable-next-line
      const type = WebRTC.NETCALL_TYPE_AUDIO;
      const account = this.info.mastImId;

      if (!account || !this.netcall) {
        errorMessage('网络电话缺少必要的数据，请关闭重试！');
        return;
      }

      this.log('发起呼叫');
      Ring.playConnectingRing();

      this.changeStateToCalling();

      this.netcall.call({
        type,
        account,
        webrtcEnable: true,
        pushConfig: {
          enable: true,
          needBadge: true,
          needPushNick: false,
          pushContent: '啄木鸟派单员来电话了，点击接听',
          pushPayload: JSON.stringify({
            title: '网络电话',
            pushTitle: '网络电话'
          }),
          custom: JSON.stringify({
            key: 'value'
          }),
          forceKeepCalling: true
        },
        sessionConfig: {
        }
      }).then(obj => {
        // 设置超时计时器
        this.callTimer = setTimeout(() => {
          if (!this.netcall.callAccepted) {
            // this.pushContent('网络电话未接听', '啄木鸟派单员刚才来电话了');
            infoMessage('您所呼叫暂时无人接听，请稍后再拨');
            Ring.playNoResponseRing(() => {
              this.cancelAudioCall();
            });
          }
        }, 1000 * 30);
      }, ({ event }) => {
        const error = event && event.event;

        if (error) {
          // 被叫不在线
          if (error.code === 11001) {
            errorMessage('当前师傅已离线!');
          } else {
            errorMessage(error.message);
          }
        } else {
          errorMessage('遇到未知错误，呼叫失败！');
        }

        this.cancelAudioCall();
      });
    },
    changeState (state) {
      this.state = STATUS[state];
    },
    changeStateToFree () {
      this.changeState('free');
    },
    changeStateToCalling () {
      this.changeState('calling');
    },
    changeStateToTalking () {
      this.changeState('talking');
    },
    cancelAudioCall () {
      this.changeStateToFree();
      this.clearCallTimer();
      this.clearRingPlay();
      this.netcall.hangup();
      this.resetWhenHangup();
    },
    onCallAccepted () {
      this.clearCallTimer();
      this.clearRingPlay();
      Promise.resolve().then(() => {
        this.log('开始webrtc连接');
        return this.netcall.startRtc();
      }).then(() => {
        this.log('webrtc连接成功');
        this.log('启动音频设备');
        return this.startDeviceAudioIn();
      }).then(() => {
        this.log('停止摄像头设备');
        return this.stopDeviceVideo();
      }).then(() => {
        this.changeStateToTalking();
        this.setCaptureVolume(255);
        this.setPlayVolume(255);
        successMessage('连接成功');
      }).catch((e) => {
        this.log('连接出错');
        errorMessage('连接出错，请重试');

        if (/webrtc兼容开关/i.test(e)) {
          this.$alert('无法接通!请让呼叫方打开"WebRTC兼容开关"，方可正常通话', '发生错误', {
            confirmButtonText: '知道了，挂断',
            type: 'error',
            callback: () => {
              this.cancelAudioCall();
            }
          });
        }
      });
    },
    onCallRejected () {
      Ring.playRejectRing(() => {
        this.cancelAudioCall();
      });
    },
    onHangup () {
      successMessage('通话结束');
      Ring.stopRing();
      this.changeStateToFree();
      this.resetWhenHangup();
    },
    resetWhenHangup () {
      this.clearCallTimer();
      this.stopDeviceAudioIn();
      this.stopDeviceAudioOutChat();
    },
    clearCallTimer () {
      if (this.callTimer) {
        clearTimeout(this.callTimer);
        this.callTimer = null;
      }
    },
    clearRingPlay () {
      Ring.stopRing();
    },
    startDeviceAudioIn () {
      const netcall = this.netcall;

      return netcall.startDevice({
        type: WebRTC.DEVICE_TYPE_AUDIO_IN
      }).then(() => {
        // 通知对方自己开启了麦克风
        netcall.control({
          command: WebRTC.NETCALL_CONTROL_COMMAND_NOTIFY_AUDIO_ON
        });
      }).catch(() => {
        // 通知对方自己的摄像头不可用
        netcall.control({
          command: WebRTC.NETCALL_CONTROL_COMMAND_NOTIFY_AUDIO_OFF
        });
        errorMessage('启动麦克风失败');
      });
    },
    stopDeviceAudioIn () {
      const netcall = this.netcall;

      return netcall.stopDevice(WebRTC.DEVICE_TYPE_AUDIO_IN).then(() => {
        // 通知对方自己关闭了麦克风
        netcall.control({
          command: WebRTC.NETCALL_CONTROL_COMMAND_NOTIFY_AUDIO_OFF
        });
      });
    },
    startDeviceAudioOutChat () {
      return this.netcall.startDevice({
        type: WebRTC.DEVICE_TYPE_AUDIO_OUT_CHAT
      }).then(() => {
        console.log('播放对方的声音成功');
      }).catch(() => {
        errorMessage('播放对方的声音失败');
      });
    },
    stopDeviceAudioOutChat () {
      return this.netcall.stopDevice(WebRTC.DEVICE_TYPE_AUDIO_OUT_CHAT);
    },
    stopDeviceVideo () {
      const netcall = this.netcall;

      return netcall.stopDevice(WebRTC.DEVICE_TYPE_VIDEO).then(() => {
        // 通知对方自己关闭了摄像头
        netcall.control({
          command: WebRTC.NETCALL_CONTROL_COMMAND_NOTIFY_VIDEO_OFF
        });
      });
    },
    sendCustomMsg (options) {
      this.nim.sendCustomMsg(options);
    },
    pushContent (title, content) {
      this.sendCustomMsg({
        scene: 'p2p',
        needPushNick: false,
        pushContent: content,
        pushPayload: JSON.stringify({
          pushTitle: title
        }),
        to: this.info.mastImId
      });
    },
    log () {
      const message = [].join.call(arguments, ' ');
      console.log('%c' + message, 'color: green;font-size:16px;');
    }
  }
};
</script>

<style lang="scss" scoped>

.netcall-container {
  display: flex;
  justify-content: center;
  align-items: center;
  height: 100vh;
  background-image: url('/static/plugins/netcall/img/bg_page.jpg');
  background-size: cover;

  .netcall-box {
    display: flex;
    flex-direction: column;
    align-items: center;
    padding: 50px 0 30px;
    width: 200px;

    .nickname {
      color: #fff;
    }

    .tips, .control {
      margin-bottom: 20px;
      height: 30px;
      color: #999;
    }

    .actions {
      margin-top: 30px;
    }
  }
}

.iconfont {
  font-size: 12px;
}
</style>
